home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / packet / tcpip / amiga / asrc29k.lha / domain.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-08  |  19.3 KB  |  895 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include "global.h"
  4. #include "mbuf.h"
  5. #include "timer.h"
  6. #include "netuser.h"
  7. #include "socket.h"
  8. #include "cmdparse.h"
  9. #include "proc.h"
  10. #include "domain.h"
  11. #include "commands.h"
  12.  
  13. static struct dserver *Dlist;        /* List of potential servers */
  14. static struct dserver *Dserver;        /* Current one being used */
  15. static char *Dsuffix;            /* Default suffix for names without periods */
  16. static int Ddebug = 0;
  17. static char *Dtypes[] = {
  18.     "",
  19.     "A",
  20.     "NS",
  21.     "MD",
  22.     "MF",
  23.     "CNAME",
  24.     "SOA",
  25.     "MB",
  26.     "MG",
  27.     "MR",
  28.     "NULL",
  29.     "WKS",
  30.     "PTR",
  31.     "HINFO",
  32.     "MINFO",
  33.     "MX",
  34.     "TXT"
  35. };
  36. static int Ndtypes = 17;
  37. static char delim[] = " \t\r\n";
  38. static struct {
  39.     char *name;
  40.     int32 address;
  41. } cache;
  42.  
  43. static struct rr *dfind __ARGS((FILE *dbase,char *name,int type));
  44. static int doadds __ARGS((int argc,char *argv[],void *p));
  45. static int dodropds __ARGS((int argc,char *argv[],void *p));
  46. static int dolistds __ARGS((int argc,char *argv[],void *p));
  47. static int dosuffix __ARGS((int argc,char *argv[],void *p));
  48. static int dodtrace __ARGS((int argc,char *argv[],void *p));
  49. static void dumpdomain __ARGS((struct dhdr *dhdr,int32 rtt));
  50. static void free_dhdr __ARGS((struct dhdr *dp));
  51. static void free_qu __ARGS((struct quest *qp));
  52. static void free_rr __ARGS((struct rr *rrp));
  53. static struct rr *getrr __ARGS((FILE *fp));
  54. static int isaddr __ARGS((char *s));
  55. static void cache_response __ARGS((struct dhdr *dhdr));
  56. static void putrr __ARGS((FILE *fp,struct rr *rrp));
  57. static int res_mkquery __ARGS((int16 op,char *dname,int16 class,int16 type,
  58.     char *data,int16 datalen,int16 newrr,char *buffer,int16 buflen));
  59. static int rrcmp __ARGS((struct rr *rr1,struct rr *rr2));
  60. static int sendquery __ARGS((int32 server,char *name,int type,int32 timeout,
  61.     struct mbuf **bpp));
  62.  
  63. static struct cmds Dcmds[] = {
  64.     "addserver",    doadds,        0, 2, NULLCHAR,
  65.     "dropserver",    dodropds,    0, 2, NULLCHAR,
  66.     "listservers",    dolistds,    0, 0, NULLCHAR,
  67.     "suffix",    dosuffix,    0, 0, NULLCHAR,
  68.     "trace",    dodtrace,    0, 0, NULLCHAR,
  69.     NULLCHAR,
  70. };
  71.  
  72. static int
  73. dodtrace(argc,argv,p)
  74. int argc;
  75. char *argv[];
  76. void *p;
  77. {
  78.     return setbool(&Ddebug,"Domain trace",argc,argv);
  79. }
  80.  
  81. int
  82. dodomain(argc,argv,p)
  83. int argc;
  84. char *argv[];
  85. void *p;
  86. {
  87.     if(argc == 1)
  88.         return dolistds(argc,argv,p);
  89.     return subcmd(Dcmds,argc,argv,p);    
  90. }
  91.  
  92. static int
  93. dosuffix(argc,argv,p)
  94. int argc;
  95. char *argv[];
  96. void *p;
  97. {
  98.     if(argc < 2){
  99.         if(Dsuffix != NULLCHAR)
  100.             tprintf("%s\n",Dsuffix);
  101.         return 0;
  102.     }
  103.     free(Dsuffix);
  104.     Dsuffix = strdup(argv[1]);
  105.     return 0;
  106. }
  107. static int
  108. doadds(argc,argv,p)
  109. int argc;
  110. char *argv[];
  111. void *p;
  112. {
  113.     struct dserver *dp;
  114.     int32 address;
  115.  
  116.     if((address = resolve(argv[1])) == 0){
  117.         tprintf("Resolver %s unknown\n",argv[1]);
  118.         return 1;
  119.     }
  120.     dp = (struct dserver *)callocw(1,sizeof(struct dserver));
  121.     dp->address = address;
  122.     dp->srtt = (5L * 1000) / MSPTICK; /* About 5 sec */
  123.     dp->mdev = 0;
  124.     dp->timeout = 2 * dp->mdev + dp->srtt + 3;
  125.     dp->next = Dlist;
  126.     if(dp->next != NULLDOM)
  127.         dp->next->prev = dp;
  128.     Dlist = dp;
  129.     Dserver = dp;    /* Make this the first one we try next */
  130.     return 0;
  131. }
  132. static int
  133. dodropds(argc,argv,p)
  134. int argc;
  135. char *argv[];
  136. void *p;
  137. {
  138.     struct dserver *dp;
  139.     int32 addr;
  140.  
  141.     addr = resolve(argv[1]);
  142.     for(dp = Dlist;dp != NULLDOM;dp = dp->next)
  143.         if(addr == dp->address)
  144.             break;
  145.  
  146.     if(dp == NULLDOM){
  147.         tprintf("Not found\n");
  148.         return 1;
  149.     }
  150.     if(dp->prev != NULLDOM)
  151.         dp->prev->next = dp->next;
  152.     else
  153.         Dlist = dp->next;
  154.     if(dp->next != NULLDOM)
  155.         dp->next->prev = dp->prev;
  156.  
  157.     if(Dserver == dp)
  158.         Dserver = Dlist;
  159.     free((char *)dp);
  160.     return 0;
  161. }
  162. static int
  163. dolistds(argc,argv,p)
  164. int argc;
  165. char *argv[];
  166. void *p;
  167. {
  168.     register struct dserver *dp;
  169.  
  170.     tprintf("Server address      srtt    mdev    timeout\
  171.  queries responses\n");
  172.     for(dp = Dlist;dp != NULLDOM;dp = dp->next){
  173.         tprintf("%-20s%-8lu%-8lu%-8lu%-8lu%-8lu\n",
  174.          inet_ntoa(dp->address),
  175.          dp->srtt * MSPTICK,
  176.          dp->mdev * MSPTICK,
  177.          dp->timeout * MSPTICK,
  178.          dp->queries,dp->responses);
  179.     }
  180.     return 0;
  181. }
  182.  
  183. /* Search local domain file, starting at current position,
  184.  * for resource record of specified type.
  185.  * If a record is found, the domain file pointer is left just after it. If
  186.  * not, it is left at end of file.
  187.  */
  188. static struct rr *
  189. dfind(dbase,name,type)
  190. FILE *dbase;
  191. char *name;
  192. int type;
  193. {
  194.     struct rr *rrp;
  195.     int nlen;
  196.  
  197.     while((rrp = getrr(dbase)) != NULLRR){
  198.         if((nlen = strlen(name)) == strlen(rrp->name)
  199.          && strnicmp(name,rrp->name,nlen) == 0
  200.          && rrp->class == CLASS_IN
  201.          && (type == TYPE_ANY || rrp->type == type))
  202.             break;
  203.         free_rr(rrp);
  204.         pwait(NULL);    /* Give up CPU for a while, this is slow */
  205.     }
  206.     return rrp;
  207. }
  208. static struct rr *
  209. getrr(fp)
  210. FILE *fp;
  211. {
  212.     char *line,*strtok();
  213.     struct rr *rrp;
  214.     char *name,*ttl,*class,*type,*data;
  215.     int i;
  216.  
  217.     line = mallocw(256);
  218.     /* Search file */
  219.     while(fgets(line,256,fp),!feof(fp)){
  220.         if(line[0] != '#')
  221.             break;
  222.     }
  223.     if(feof(fp)){
  224.         free(line);
  225.         return NULLRR;
  226.     }
  227.      rrp = (struct rr *)callocw(1,sizeof(struct rr));
  228.     name = strtok(line,delim);
  229.     ttl = strtok(NULLCHAR,delim);
  230.     class = strtok(NULLCHAR,delim);
  231.     type = strtok(NULLCHAR,delim);
  232.     data = strtok(NULLCHAR,delim);
  233.     
  234.     i = strlen(name);
  235.     if(name[i-1] != '.'){
  236.         /* Tack on a trailing period if it's not there */
  237.         rrp->name = mallocw(i+2);
  238.         strcpy(rrp->name,name);
  239.         strcat(rrp->name,".");
  240.     } else 
  241.         rrp->name = strdup(name);
  242.     
  243.     if(!isdigit(ttl[0])){
  244.         /* Optional ttl field is missing; slide the other fields over */
  245.         data = type;
  246.         type = class;
  247.         class = ttl;
  248.         ttl = NULLCHAR;
  249.     } else {
  250.         rrp->ttl = atol(ttl);
  251.     }
  252.     for(i=0;i<NRLIST;i++){
  253.         if(strcmp(type,Dtypes[i]) == 0){
  254.             rrp->type = i;
  255.             break;
  256.         }
  257.     }
  258.     if(strcmp(class,"IN") == 0)
  259.         rrp->class = CLASS_IN;
  260.  
  261.     if(data == NULLCHAR){
  262.         /* Empty record, just return */
  263.         free(line);
  264.         return rrp;
  265.     }
  266.     switch(rrp->type){
  267.     case TYPE_CNAME:
  268.     case TYPE_MB:
  269.     case TYPE_MG:
  270.     case TYPE_MR:
  271.     case TYPE_NS:
  272.     case TYPE_PTR:
  273.     case TYPE_TXT:
  274.         rrp->rdlength = strlen(data);
  275.         rrp->rdata.name = strdup(data);
  276.         break;
  277.     case TYPE_A:
  278.         rrp->rdlength = 4;
  279.         rrp->rdata.addr = aton(data);
  280.         break;
  281.     case TYPE_HINFO:
  282.         rrp->rdlength = strlen(data);
  283.         rrp->rdata.hinfo.cpu = strdup(data);
  284.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  285.             rrp->rdlength += strlen(data);
  286.             rrp->rdata.hinfo.os = strdup(data);
  287.         }
  288.         break;
  289.     case TYPE_MX:
  290.         rrp->rdata.mx.pref = atoi(data);
  291.         rrp->rdlength = 2;
  292.  
  293.         /* Get domain name of exchanger */
  294.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  295.             rrp->rdlength += strlen(data);
  296.             rrp->rdata.mx.exch = strdup(data);
  297.         }
  298.         break;
  299.     case TYPE_SOA:
  300.         /* Get domain name of master name server */
  301.         rrp->rdlength = strlen(data);
  302.         rrp->rdata.soa.mname = strdup(data);
  303.  
  304.         /* Get domain name of irresponsible person */
  305.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  306.             rrp->rdata.soa.rname = strdup(data);
  307.             rrp->rdlength += strlen(data);
  308.         }
  309.         data = strtok(NULLCHAR,delim);
  310.         rrp->rdata.soa.serial = atol(data);
  311.         data = strtok(NULLCHAR,delim);
  312.         rrp->rdata.soa.refresh = atol(data);
  313.         data = strtok(NULLCHAR,delim);
  314.         rrp->rdata.soa.retry = atol(data);
  315.         data = strtok(NULLCHAR,delim);
  316.         rrp->rdata.soa.expire = atol(data);
  317.         data = strtok(NULLCHAR,delim);
  318.         rrp->rdata.soa.minimum = atol(data);
  319.         rrp->rdlength += 20;
  320.         break;
  321.     }
  322.     free(line);
  323.     return rrp;
  324. }
  325. /* Search for address record in local database, looking first for PTR
  326.  * and CNAME records. Return values:
  327.  *  0xffffffff    Not found (domain name may exist, but we don't know yet)
  328.  *  0        Domain name definitely doesn't exist (we have a null record)
  329.  */
  330. int32
  331. dresolve(name)
  332. char *name;
  333. {
  334.     register struct rr *rrp;
  335.     char *sname,*tmp;
  336.     int32 addr;
  337.     FILE *dbase;
  338.     int crecurse = 0;
  339.     int found = 0;
  340.  
  341.     if(cache.name != NULLCHAR && strcmp(cache.name,name) == 0)
  342.         return cache.address;
  343.  
  344.     if((dbase = fopen(Dfile,READ_TEXT)) == NULLFILE)
  345.         return 0xffffffff;
  346.  
  347.     sname = strdup(name);
  348.  
  349.     while(!found && (rrp = dfind(dbase,sname,TYPE_ANY)) != NULLRR){
  350.         switch(rrp->type){
  351.         case TYPE_A:
  352.             /* All set! */
  353.             found++;
  354.             if(rrp->rdlength == 0)
  355.                 addr = 0;    /* Neg response */
  356.             else
  357.                 addr = rrp->rdata.addr;
  358.             break;
  359.         case TYPE_CNAME:
  360.         case TYPE_PTR:
  361.             if(++crecurse == MAXCNAME){
  362.                 /* Too many CNAME recursions */
  363.                 found++;
  364.                 break;
  365.             }
  366.             /* Look for what it points to */
  367.             tmp = strdup(rrp->rdata.name);
  368.             free(sname);
  369.             sname = tmp;
  370.             rewind(dbase);    /* Start again */
  371.             break;
  372.         }
  373.         free_rr(rrp);
  374.     }
  375. done:    fclose(dbase);
  376.     if(found){
  377.         free(cache.name);
  378.         cache.name = strdup(name);
  379.         cache.address = addr;
  380.     } else
  381.         addr = 0xffffffff;
  382.     free(sname);
  383.     return addr;
  384. }
  385.  
  386. /* Main entry point for domain name -> address resolution. Returns 0 if
  387.  * name is definitely not valid.
  388.  */
  389. int32
  390. resolve(name)
  391. char *name;
  392. {
  393.     int32 addr;
  394.     struct dhdr dhdr;
  395.     struct dserver *dp = Dserver;
  396.     char *sname,*tmp;
  397.     int len,i;
  398.     int32 rtt,abserr;
  399.     struct mbuf *bp;
  400.     struct rr *rrp;
  401.     int crecurse = 0;
  402.  
  403.     if(name == NULLCHAR)
  404.         return 0;
  405.  
  406.     if(*name == '[')
  407.         return aton(name + 1);
  408.  
  409.     if(isaddr(name))
  410.         return aton(name);
  411.  
  412.  
  413.     sname = strdup(name);
  414.     if(strchr(sname,'.') == NULLCHAR && Dsuffix != NULLCHAR){
  415.         /* Append default suffix */
  416.         tmp = mallocw(strlen(sname)+strlen(Dsuffix)+2);
  417.         sprintf(tmp,"%s.%s",sname,Dsuffix);
  418.         free(sname);
  419.         sname = tmp;
  420.     }
  421.     if(sname[strlen(sname)-1] != '.'){
  422.         /* Append trailing dot */
  423.         tmp = mallocw(strlen(sname)+2);
  424.         sprintf(tmp,"%s.",sname);
  425.         free(sname);
  426.         sname = tmp;
  427.     }
  428.     while((addr = dresolve(sname)) == 0xffffffff){
  429.         /* Not found in local file. Query the domain servers. */
  430.         if(dp == NULLDOM)
  431.             break;        /* no servers! */
  432.         for(;;){
  433.             dp->queries++;
  434.             len = sendquery(dp->address,sname,TYPE_A,dp->timeout,&bp);
  435.             if(len > 0)
  436.                 break;    /* Got a response */
  437.             if(errno == EABORT){
  438.                 addr = 0;    /* Killed by "reset" command */
  439.                 break;
  440.             }
  441.             /* Timeout; back off this one and try another server */
  442.             dp->timeout <<= 1;
  443.             if((dp = dp->next) == NULLDOM)
  444.                 dp = Dlist;
  445.         }
  446.         if(len <= 0)
  447.             break;
  448.         dp->responses++;
  449.         ntohdomain(&dhdr,&bp);    /* Convert response to local format */
  450.  
  451.         /* Compute and update the round trip time */
  452.         rtt = (int32) ((int16)Clock - dhdr.id);
  453.         abserr = rtt > dp->srtt ? rtt - dp->srtt : dp->srtt - rtt;
  454.         dp->srtt = ((AGAIN-1) * dp->srtt + rtt + (AGAIN/2)) >> LAGAIN;
  455.         dp->mdev = ((DGAIN-1) * dp->mdev + abserr + (DGAIN/2)) >> LDGAIN;
  456.         dp->timeout = 2 * dp->mdev + dp->srtt + 3;
  457.  
  458.         if(Ddebug)
  459.             dumpdomain(&dhdr,rtt);
  460.         cache_response(&dhdr);    /* Add records to local disk file */
  461.         /* Look for an answer in this response */
  462.         for(i=0;i<dhdr.ancount;i++){
  463.             rrp = dhdr.ans[i];
  464.             if(strnicmp(rrp->name,sname,strlen(sname)) != 0)
  465.                 continue;
  466.             /* Got one! */
  467.             switch(rrp->type){
  468.             case TYPE_CNAME:
  469.                 /* Change the query name to the cname
  470.                  * and go back again
  471.                  */
  472.                 if(++crecurse == MAXCNAME){
  473.                     /* Too many CNAME recursions */
  474.                     addr = 0;
  475.                     break;
  476.                 }
  477.                 free(sname);
  478.                 sname = strdup(rrp->rdata.name);
  479.                 /* Go back and rescan the response */
  480.                 i = -1;
  481.                 continue;
  482.             case TYPE_A:
  483.                 if(rrp->rdlength == 0)
  484.                     addr = 0;
  485.                 else
  486.                     addr = rrp->rdata.addr;
  487.                 break;
  488.             }
  489.             break;
  490.         }
  491.         free_dhdr(&dhdr);
  492.         if(addr != 0xffffffff)
  493.             break;
  494.     }
  495.     free(sname);
  496.     if(addr == 0xffffffff)
  497.         addr = 0;
  498.     return addr;
  499. }
  500. /* Send a query to a server */
  501. static int
  502. sendquery(server,name,type,timeout,bpp)
  503. int32 server;        /* Server's IP address */
  504. char *name;        /* Domain name being looked up */
  505. int type;        /* Type of resource record sought */
  506. int32 timeout;        /* Query timeout */
  507. struct mbuf **bpp;    /* Place to stash reply */
  508. {
  509.     char *buf;
  510.     int len;
  511.     struct sockaddr_in server_in;
  512.     int s,rval;
  513.  
  514.     s = socket(AF_INET,SOCK_DGRAM,0);
  515.     buf = mallocw(512);
  516.     len = res_mkquery(0,name,CLASS_IN,TYPE_A,NULLCHAR,0,0,buf,512);
  517.     server_in.sin_family = AF_INET;
  518.     server_in.sin_port = IPPORT_DOMAIN;
  519.     server_in.sin_addr.s_addr = server;
  520.     if(Ddebug){
  521.         printf("resolve: querying server %s for %s\n",
  522.          inet_ntoa(server),name);
  523.     }
  524.     sendto(s,buf,len,0,(char *)&server_in,sizeof(server_in));
  525.     free(buf);
  526.     alarm(max(timeout,1));
  527.     /* Wait for something to happen */
  528.     rval = recv_mbuf(s,bpp,0,NULLCHAR,0);
  529.     alarm(0L);
  530.     close_s(s);
  531.     return rval;
  532. }
  533.  
  534. static int
  535. res_mkquery(op,dname,class,type,data,datalen,newrr,buffer,buflen)
  536. int16 op;    /* operation */
  537. char *dname;    /* Domain name */
  538. int16 class;    /* Class of inquiry (IN, etc) */
  539. int16 type;    /* Type of inquiry (A, MX, etc) */
  540. char *data;
  541. int16 datalen;
  542. int16 newrr;
  543. char *buffer;    /* Area for query */
  544. int16 buflen;    /* Length of same */
  545. {
  546.     char *cp,*cp1;
  547.     int16 parameter;
  548.     int16 dlen,len;
  549.  
  550.     cp = buffer;
  551.     cp = put16(cp,(int16)Clock);    /* Use clock for timestamping */
  552.     parameter = 0x100;    /* Recursion desired */
  553.     cp = put16(cp,parameter);
  554.     cp = put16(cp,1);
  555.     cp = put16(cp,0);
  556.     cp = put16(cp,0);
  557.     cp = put16(cp,0);
  558.     dlen = strlen(dname);
  559.     for(;;){
  560.         /* Look for next dot */
  561.         cp1 = strchr(dname,'.');
  562.         if(cp1 != NULLCHAR)
  563.             len = cp1-dname;    /* More to come */
  564.         else
  565.             len = dlen;    /* Last component */
  566.         *cp++ = len;        /* Write length of component */
  567.         if(len == 0)
  568.             break;
  569.         /* Copy component up to (but not including) dot */
  570.         strncpy(cp,dname,len);
  571.         cp += len;
  572.         if(cp1 == NULLCHAR){
  573.             *cp++ = 0;    /* Last one; write null and finish */
  574.             break;
  575.         }
  576.         dname += len+1;
  577.         dlen -= len+1;
  578.     }
  579.     cp = put16(cp,type);
  580.     cp = put16(cp,class);
  581.     return cp - buffer;
  582. }
  583. /* Append any non-duplicate resource records to the local file */
  584. static void
  585. cache_response(dhdr)
  586. struct dhdr *dhdr;
  587. {
  588.     FILE *fp;
  589.     int i;
  590.     long ttl = 500;    /* Default TTL for negative records without SOA */
  591.     struct rr *rrp,*frrp;
  592.     struct quest *qp;
  593.  
  594.     fp = fopen(Dfile,APPEND_TEXT);
  595.     if(fp == NULLFILE){
  596.         printf("Can't append to %s!!\n",Dfile);
  597.         return;
  598.     }
  599.     /* Scan domain file looking for duplicates */
  600.     while((frrp = getrr(fp)) != NULLRR){
  601.         for(i=0;i< dhdr->ancount;i++){
  602.             rrp = dhdr->ans[i];
  603.             if(rrp->type == TYPE_SOA)
  604.                 ttl = rrp->ttl;
  605.             if(rrcmp(rrp,frrp) == 0)
  606.                 rrp->dupe = 1;
  607.         }
  608.         for(i=0;i< dhdr->nscount;i++){
  609.             rrp = dhdr->ns[i];
  610.             if(rrp->type == TYPE_SOA)
  611.                 ttl = rrp->ttl;
  612.             if(rrcmp(rrp,frrp) == 0)
  613.                 rrp->dupe = 1;
  614.         }
  615.         for(i=0;i< dhdr->arcount;i++){
  616.             rrp = dhdr->add[i];
  617.             if(rrp->type == TYPE_SOA)
  618.                 ttl = rrp->ttl;
  619.             if(rrcmp(rrp,frrp) == 0)
  620.                 rrp->dupe = 1;
  621.         }
  622.         free_rr(frrp);
  623.     }
  624.     /* Now append any non-duplicate records */
  625.     fseek(fp,0L,2);
  626.     for(i=0;i< dhdr->ancount;i++){
  627.         rrp = dhdr->ans[i];
  628.         if(!rrp->dupe)
  629.             putrr(fp,rrp);
  630.     }
  631.     for(i=0;i< dhdr->nscount;i++){
  632.         rrp = dhdr->ns[i];
  633.         if(!rrp->dupe)
  634.             putrr(fp,rrp);
  635.     }
  636.     for(i=0;i< dhdr->arcount;i++){
  637.         rrp = dhdr->add[i];
  638.         if(!rrp->dupe)
  639.             putrr(fp,rrp);
  640.     }
  641.     if(dhdr->aa && (dhdr->rcode == NAME_ERROR || dhdr->ancount == 0)){
  642.         /* Add negative reply to file. This assumes that there was
  643.          * only one question, which is true for all questions we send.
  644.          */
  645.         qp = dhdr->qlist[0];
  646.         rrp = (struct rr *)callocw(1,sizeof(struct rr));
  647.         rrp->name = strdup(qp->qname);
  648.         rrp->type = qp->qtype;
  649.         rrp->class = qp->qclass;
  650.         rrp->ttl = ttl;
  651.         rrp->rdlength = 0;    /* no data */
  652.         putrr(fp,rrp);
  653.         free_rr(rrp);
  654.     }
  655.     fclose(fp);
  656. }
  657. /* Print a resource record */
  658. static void
  659. putrr(fp,rrp)
  660. FILE *fp;
  661. struct rr *rrp;
  662. {
  663.     if(fp == NULLFILE || rrp == NULLRR)
  664.         return;
  665.  
  666.     fprintf(fp,"%s\t%lu",rrp->name,rrp->ttl);
  667.     if(rrp->class == CLASS_IN)
  668.         fprintf(fp,"\tIN");
  669.     else
  670.         fprintf(fp,"\t%u",rrp->class);
  671.     if(rrp->type < Ndtypes)
  672.         fprintf(fp,"\t%s",Dtypes[rrp->type]);
  673.     else
  674.         fprintf(fp,"\t%u",rrp->type);
  675.     if(rrp->rdlength == 0){
  676.         /* Null data portion, indicates nonexistent record */
  677.         fprintf(fp,"\n");
  678.         return;
  679.     }
  680.     switch(rrp->type){
  681.     case TYPE_CNAME:
  682.     case TYPE_MB:
  683.     case TYPE_MG:
  684.     case TYPE_MR:
  685.     case TYPE_NS:
  686.     case TYPE_PTR:
  687.     case TYPE_TXT:
  688.         /* These are all printable text strings */
  689.         fprintf(fp,"\t%s\n",rrp->rdata.data);
  690.         break;
  691.     case TYPE_A:
  692.         fprintf(fp,"\t%s\n",inet_ntoa(rrp->rdata.addr));
  693.         break;
  694.     case TYPE_MX:
  695.         fprintf(fp,"\t%u\t%s\n",rrp->rdata.mx.pref,
  696.          rrp->rdata.mx.exch);
  697.         break;
  698.     case TYPE_SOA:
  699.         fprintf(fp,"\t%s\t%s\t%lu\t%lu\t%lu\t%lu\t%lu\n",
  700.          rrp->rdata.soa.mname,rrp->rdata.soa.rname,
  701.          rrp->rdata.soa.serial,rrp->rdata.soa.refresh,
  702.          rrp->rdata.soa.retry,rrp->rdata.soa.expire,
  703.          rrp->rdata.soa.minimum);
  704.         break;
  705.     default:
  706.         fprintf(fp,"\n");
  707.         break;
  708.     }
  709. }
  710. /* Free a domain message */
  711. static void
  712. free_dhdr(dp)
  713. struct dhdr *dp;
  714. {
  715.     int i;
  716.  
  717.     if(dp->qdcount != 0){
  718.         for(i=0;i<dp->qdcount;i++)
  719.             free_qu(dp->qlist[i]);
  720.         free((char *)dp->qlist);
  721.     }
  722.     if(dp->ancount != 0){
  723.         for(i=0;i<dp->ancount;i++)
  724.             free_rr(dp->ans[i]);
  725.         free((char *)dp->ans);
  726.     }
  727.     if(dp->nscount != 0){
  728.         for(i=0;i<dp->nscount;i++)
  729.             free_rr(dp->ns[i]);
  730.         free((char *)dp->ns);
  731.     }
  732.     if(dp->arcount != 0){
  733.         for(i=0;i<dp->arcount;i++)
  734.             free_rr(dp->add[i]);
  735.         free((char *)dp->add);
  736.     }
  737. }
  738.  
  739. /* Free a question record */
  740. static void
  741. free_qu(qp)
  742. struct quest *qp;
  743. {
  744.     free(qp->qname);
  745.     free((char *)qp);
  746. }
  747.  
  748. /* Free a resource record */
  749. static void
  750. free_rr(rrp)
  751. struct rr *rrp;
  752. {
  753.     if(rrp == NULLRR)
  754.         return;
  755.     free(rrp->name);
  756.     if(rrp->rdlength != 0){
  757.         switch(rrp->type){
  758.         case TYPE_CNAME:
  759.         case TYPE_MB:
  760.         case TYPE_MG:
  761.         case TYPE_MR:
  762.         case TYPE_NS:
  763.         case TYPE_PTR:
  764.             free(rrp->rdata.name);
  765.             break;
  766.         case TYPE_A:
  767.             break;    /* Nothing allocated in rdata section */
  768.         case TYPE_HINFO:
  769.             free(rrp->rdata.hinfo.cpu);
  770.             free(rrp->rdata.hinfo.os);
  771.             break;
  772.         case TYPE_MX:
  773.             free(rrp->rdata.mx.exch);
  774.             break;
  775.         case TYPE_SOA:
  776.             free(rrp->rdata.soa.mname);
  777.             free(rrp->rdata.soa.rname);
  778.             break;
  779.         case TYPE_TXT:
  780.             free(rrp->rdata.data);
  781.             break;
  782.         }
  783.     }
  784.     free((char *)rrp);
  785. }
  786. /* Compare two resource records, returning 0 if equal, nonzero otherwise */
  787. static int
  788. rrcmp(rr1,rr2)
  789. register struct rr *rr1,*rr2;
  790. {
  791.     int i;
  792.  
  793.     if(rr1 == NULLRR || rr2 == NULLRR)
  794.         return -1;
  795.     if((i = strlen(rr1->name)) != strlen(rr2->name))
  796.         return 1;
  797.     if((i = strnicmp(rr1->name,rr2->name,i)) != 0)
  798.         return i;
  799.     if(rr1->type != rr2->type)
  800.         return 2;
  801.     if(rr1->class != rr2->class)
  802.         return 3;
  803.     /* Note: rdlengths are not compared because they vary depending
  804.      * on the representation (ASCII or encoded) this record was
  805.      * generated from.
  806.      */
  807.     switch(rr1->type){
  808.     case TYPE_A:
  809.         i = rr1->rdata.addr != rr2->rdata.addr;
  810.         break;
  811.     case TYPE_SOA:
  812.         i = rr1->rdata.soa.serial != rr2->rdata.soa.serial;
  813.         break;
  814.     case TYPE_HINFO:
  815.         i = strcmp(rr1->rdata.hinfo.cpu,rr2->rdata.hinfo.cpu) ||
  816.             strcmp(rr1->rdata.hinfo.os,rr2->rdata.hinfo.os);
  817.         break;
  818.     case TYPE_MX:
  819.         i = strcmp(rr1->rdata.mx.exch,rr2->rdata.mx.exch);
  820.         break;
  821.     case TYPE_MB:
  822.     case TYPE_MG:
  823.     case TYPE_MR:
  824.     case TYPE_NULL:
  825.     case TYPE_WKS:
  826.     case TYPE_PTR:
  827.     case TYPE_MINFO:
  828.     case TYPE_TXT:
  829.     case TYPE_NS:
  830.         i = strcmp(rr1->rdata.data,rr2->rdata.data);
  831.         break;
  832.     case TYPE_MD:
  833.     case TYPE_MF:
  834.     case TYPE_CNAME:
  835.         i = strcmp(rr1->rdata.data,rr2->rdata.data);
  836.         break;
  837.     }
  838.     return i;
  839. }
  840. /* Return 1 if string appears to be an IP address in dotted decimal;
  841.  * return 0 otherwise (i.e., if string is a domain name)
  842.  */
  843. static int
  844. isaddr(s)
  845. register char *s;
  846. {
  847.     char c;
  848.  
  849.     if(s == NULLCHAR)
  850.         return 1;    /* Can't happen */
  851.  
  852.     while((c = *s++) != '\0'){
  853.         if(!isdigit(c) && c != '.')
  854.             return 0;
  855.     }
  856.     return 1;
  857. }
  858. static void
  859. dumpdomain(dhdr,rtt)
  860. struct dhdr *dhdr;
  861. int32 rtt;
  862. {
  863.     int i;
  864.     struct rr *rrp;
  865.     struct quest *qp;
  866.  
  867.     printf("response id %u (rtt %lu sec) qr %u opcode %u aa %u tc %u rd %u ra %u rcode %u\n",
  868.      dhdr->id,((long)rtt * MSPTICK)/1000,
  869.      dhdr->qr,dhdr->opcode,dhdr->aa,dhdr->tc,dhdr->rd,
  870.      dhdr->ra,dhdr->rcode);
  871.     printf("%u questions:\n",dhdr->qdcount);
  872.     for(i=0;i< dhdr->qdcount;i++){
  873.         qp = dhdr->qlist[i];
  874.         printf("%s type %u class %u\n",qp->qname,
  875.          qp->qtype,qp->qclass);
  876.     }
  877.     printf("%u answers:\n",dhdr->ancount);
  878.     for(i=0;i< dhdr->ancount;i++){
  879.         rrp = dhdr->ans[i];
  880.         putrr(stdout,rrp);
  881.     }
  882.     printf("%u authority:\n",dhdr->nscount);
  883.     for(i=0;i< dhdr->nscount;i++){
  884.         rrp = dhdr->ns[i];
  885.         putrr(stdout,rrp);
  886.     }
  887.     printf("%u additional:\n",dhdr->arcount);
  888.     for(i=0;i< dhdr->arcount;i++){
  889.         rrp = dhdr->add[i];
  890.         putrr(stdout,rrp);
  891.     }
  892.     fflush(stdout);
  893. }
  894.  
  895.